﻿using System;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace SlamCms.Common
{
	public static class StringExtensions
	{
		private static readonly Regex _guidRegex = new Regex(@"^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$", RegexOptions.Compiled);

		public static bool IsGuid(this string inputString)
		{
			return _guidRegex.IsMatch(inputString);
		}

		public static bool IsNullOrEmpty(this string inputString)
		{
			return string.IsNullOrEmpty(inputString);
		}

	    private static readonly Regex _emailRegex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{1,4}$");

		public static bool IsValidEmailAddress(this string s)
		{
			if (s.IsNullOrEmpty())
				return false;

			return _emailRegex.IsMatch(s);
		}

		private static readonly Regex _ipAddressRegex = new Regex(@"\b([0-9]{1,3}\.){3}[0-9]{1,3}$", RegexOptions.Compiled | RegexOptions.ExplicitCapture);

		public static string ToIpAddress(this string s)
		{
			return _ipAddressRegex.Match(s).Value;
		}

		public static bool IsPrivateIp(this string s)
		{
			return _ipAddressRegex.Match(s).Success && (s.StartsWith("192.168.") || s.StartsWith("10.") || s.StartsWith("127.0.0."));
		}

		public static string GetSHA1Hash(this string text)
		{
			var sha1 = SHA1.Create();
			return text.GetHash(sha1);
		}

		public static string GetMD5Hash(this string text)
		{
			var md5 = MD5.Create();
			return text.GetHash(md5);
		}

		private static string GetHash(this string text, HashAlgorithm hashAlgorithm)
		{
			return BitConverter.ToString(hashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(text))).Replace("-", "").ToLower();
		}

		public static string F(this string inputString, params object[] args)
		{
			if (inputString.IsNullOrEmpty())
				return inputString;

			return string.Format(inputString, args);
		}

		public static string RemoveHtmlTags(this string inputString)
		{
			return Regex.Replace(inputString.Trim(), @"<[^>]*>", String.Empty);
		}

		public static string RemoveSpaces(this string inputString)
		{
			return Regex.Replace(inputString, @"\s", "");
		}

		public static string RemoveInvalidFileSystemCharacters(this string inputString)
		{
			return Regex.Replace(inputString, @"[/\<>:?|*""]", "");
		}

		public static string EncodeForPath(this string inputString)
		{
			return HttpContext.Current.Server.UrlEncode(Regex.Replace(inputString, @"[^-\w\s]|\b\w{1,2}\s", "")).Replace("+", "-").TrimEnd('-');
		}

		public static string EncodeForS3Path(this string inputString)
		{
			return HttpContext.Current.Server.UrlEncode(inputString).Replace("%20", "+");
		}

		public static string GetSlug(this string phrase)
		{
			if (phrase.IsNullOrEmpty())
				return string.Empty;

			var str = phrase.RemoveAccent().ToLower();

			// invalid chars, make into spaces
			str = Regex.Replace(str, @"[^a-z0-9\s-]", "");

			// convert multiple spaces/hyphens into one space       
			str = Regex.Replace(str, @"[\s-]+", " ").Trim();

			// trim it
			str = str.Trim();

			// hyphens
			str = Regex.Replace(str, @"\s", "-");

			return str;
		}

		public static string RemoveAccent(this string text)
		{
			if (text.IsNullOrEmpty())
				return string.Empty;

			var bytes = Encoding.GetEncoding("Cyrillic").GetBytes(text);
			return Encoding.ASCII.GetString(bytes);
		}

		public static bool Contains(this string source, string toCheck, StringComparison stringComparison)
		{
			return source.IndexOf(toCheck, stringComparison) > -1;
		}

		public static string EnsureStartsWith(this string source, string value)
		{
			if (source.StartsWith(value))
				return source;

			return value + source;
		}

		public static string EnsureEndsWith(this string source, string value)
		{
			if (source.EndsWith(value))
				return source;

			return source + value;
		}

		/// <summary>
		/// Answers true if this String is neither null or empty.
		/// </summary>
		/// <remarks>I'm also tired of typing !String.IsNullOrEmpty(s)</remarks>
		public static bool HasValue(this string s)
		{
			return !IsNullOrEmpty(s);
		}

		/// <summary>
		/// force string to be maxlen or smaller
		/// </summary>
		public static string Truncate(this string s, int maxLength)
		{
			return (s.HasValue() && s.Length > maxLength) ? s.Remove(maxLength) : s;
		}

		/// <summary>
		/// If this String is over 'maxLength', answers a new String with Length = 'maxLength', with ...
		/// as the final three characters.
		/// </summary>
		public static string TruncateWithEllipsis(this string s, int maxLength)
		{
			const string ellipsis = "...";
			return (s.HasValue() && s.Length > maxLength) ? (s.Truncate(maxLength - ellipsis.Length) + ellipsis) : s;
		}
	}
}
